package com.vviton.zyhj.common.utils;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.HashMap;
import java.util.Map;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

/**
 * Http客户端工具类 这是内部调用类，请不要在外部调用。
 *
 */
@SuppressWarnings("deprecation")
public class HttpClientUtil {
    /** SunX509 **/
    public static final String SunX509 = "SunX509";
    /** JKS **/
    public static final String JKS = "JKS";
    /** PKCS12 **/
    public static final String PKCS12 = "PKCS12";
    /** TLS **/
    public static final String TLS = "TLS";

    /**常量*/
    private static final int NUMBER = 200;

    /**
     * get HttpURLConnection
     * 
     * @param strUrl url地址
     * @return HttpURLConnection
     * @throws IOException 异常
     */
    public static HttpURLConnection getHttpURLConnection(String strUrl) throws IOException {
        URL url = new URL(strUrl);
        HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
        return httpURLConnection;
    }

    /**
     * get HttpsURLConnection
     * 
     * @param strUrl url地址
     * @return HttpsURLConnection
     * @throws IOException 异常
     */
    public static HttpsURLConnection getHttpsURLConnection(String strUrl) throws IOException {
        URL url = new URL(strUrl);
        HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
        return httpsURLConnection;
    }

    /**
     * 获取不带查询串的url
     * 
     * @param strUrl 链接地址
     * @return String
     */
    public static String getURL(String strUrl) {

        if (null != strUrl) {
            int indexOf = strUrl.indexOf("?");
            if (-1 != indexOf) {
                return strUrl.substring(0, indexOf);
            }

            return strUrl;
        }

        return strUrl;

    }

    /**
     * 获取查询串
     * 
     * @param strUrl 链接地址
     * @return String
     */
    public static String getQueryString(String strUrl) {

        if (null != strUrl) {
            int indexOf = strUrl.indexOf("?");
            if (-1 != indexOf) {
                return strUrl.substring(indexOf + 1, strUrl.length());
            }

            return "";
        }

        return strUrl;
    }

    /**
     * 查询字符串转换成Map<br/>
     * name1=key1&name2=key2&...
     * 
     * @param queryString 查询字符串
     * @return Map
     */
    @SuppressWarnings("rawtypes")
    public static Map queryString2Map(String queryString) {
        if (null == queryString || "".equals(queryString)) {
            return null;
        }

        Map m = new HashMap();
        String[] strArray = queryString.split("&");
        for (int index = 0; index < strArray.length; index++) {
            String pair = strArray[index];
            HttpClientUtil.putMapByPair(pair, m);
        }

        return m;

    }

    /**
     * 把键值添加至Map<br/>
     * pair:name=value
     * 
     * @param pair name=value
     * @param m map集合
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static void putMapByPair(String pair, Map m) {

        if (null == pair || "".equals(pair)) {
            return;
        }

        int indexOf = pair.indexOf("=");
        if (-1 != indexOf) {
            String k = pair.substring(0, indexOf);
            String v = pair.substring(indexOf + 1, pair.length());
            if (null != k && !"".equals(k)) {
                m.put(k, v);
            }
        } else {
            m.put(pair, "");
        }
    }

    /**
     * BufferedReader转换成String<br/>
     * 注意:流关闭需要自行处理
     * 
     * @param reader BufferedReader类
     * @return String
     * @throws IOException 异常
     */
    public static String bufferedReader2String(BufferedReader reader) throws IOException {
        StringBuffer buf = new StringBuffer();
        String line = null;
        while ((line = reader.readLine()) != null) {
            buf.append(line);
            buf.append("\r\n");
        }

        return buf.toString();
    }

    /**
     * 处理输出<br/>
     * 注意:流关闭需要自行处理
     * 
     * @param out 输出流
     * @param data 数据
     * @param len 长度
     * @throws IOException 异常
     */
    public static void doOutput(OutputStream out, byte[] data, int len) throws IOException {
        int dataLen = data.length;
        int off = 0;
        while (off < dataLen) {
            if (len >= dataLen) {
                out.write(data, off, dataLen);
            } else {
                out.write(data, off, len);
            }

            // 刷新缓冲区
            out.flush();

            off += len;

            dataLen -= len;
        }

    }

    /**
     * 获取SSLContext
     * 
     * @param trustFileInputStream 输入流
     * @param trustPasswd trustPasswd
     * @param keyFileInputStream 输入流
     * @param keyPasswd trustPasswd
     * @return SSLContext
     * @throws NoSuchAlgorithmException 异常
     * @throws KeyStoreException 异常
     * @throws IOException 异常
     * @throws CertificateException 异常
     * @throws UnrecoverableKeyException 异常
     * @throws KeyManagementException 异常
     */
    public static SSLContext getSSLContext(FileInputStream trustFileInputStream, String trustPasswd, FileInputStream keyFileInputStream, String keyPasswd) throws NoSuchAlgorithmException,
            KeyStoreException, CertificateException, IOException, UnrecoverableKeyException, KeyManagementException {

        // ca
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(HttpClientUtil.SunX509);
        KeyStore trustKeyStore = KeyStore.getInstance(HttpClientUtil.JKS);
        trustKeyStore.load(trustFileInputStream, HttpClientUtil.str2CharArray(trustPasswd));
        tmf.init(trustKeyStore);

        final char[] kp = HttpClientUtil.str2CharArray(keyPasswd);
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(HttpClientUtil.SunX509);
        KeyStore ks = KeyStore.getInstance(HttpClientUtil.PKCS12);
        ks.load(keyFileInputStream, kp);
        kmf.init(ks, kp);

        SecureRandom rand = new SecureRandom();
        SSLContext ctx = SSLContext.getInstance(HttpClientUtil.TLS);
        ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), rand);

        return ctx;
    }

    /**
     * 获取CA证书信息
     * 
     * @param cafile CA证书文件
     * @return Certificate
     * @throws CertificateException 异常
     * @throws IOException 异常
     */
    public static Certificate getCertificate(File cafile) throws CertificateException, IOException {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        FileInputStream in = new FileInputStream(cafile);
        Certificate cert = cf.generateCertificate(in);
        in.close();
        return cert;
    }

    /**
     * 字符串转换成char数组
     * 
     * @param str 字符串
     * @return char[]
     */
    public static char[] str2CharArray(String str) {
        if (null == str) {
            return null;
        }

        return str.toCharArray();
    }

    /**
     * 存储ca证书成JKS格式
     * 
     * @param cert cert
     * @param alias alias
     * @param password password
     * @param out out
     * @throws KeyStoreException 异常
     * @throws NoSuchAlgorithmException 异常
     * @throws CertificateException 异常
     * @throws IOException 异常
     */
    public static void storeCACert(Certificate cert, String alias, String password, OutputStream out) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
        KeyStore ks = KeyStore.getInstance("JKS");

        ks.load(null, null);

        ks.setCertificateEntry(alias, cert);

        // store keystore
        ks.store(out, HttpClientUtil.str2CharArray(password));

    }

    /**
     * 
     * String2Inputstream,(输入流). <br/>
     * Author: qiaocf <br/>
     * Create Date: 2016年3月11日 <br/>
     * ===============================================================<br/>
     * Modifier: qiaocf <br/>
     * Modify Date: 2016年3月11日 <br/>
     * Modify Description: <br/>
     * ===============================================================<br/>
     * 
     * @param str 字符串
     * @return InputStream
     * @since JDK 1.7
     */
    public static InputStream String2Inputstream(String str) {
        return new ByteArrayInputStream(str.getBytes());
    }

    /**
     * 
     * httpGet,(httpGet). <br/>
     * Author: qiaocf <br/>
     * Create Date: 2016年3月11日 <br/>
     * ===============================================================<br/>
     * Modifier: qiaocf <br/>
     * Modify Date: 2016年3月11日 <br/>
     * Modify Description: <br/>
     * ===============================================================<br/>
     * 
     * @param url url地址
     * @return ResultJson
     * @since JDK 1.7
     */
    public static ResultJson httpGet(String url) {
        ResultJson rj = new ResultJson(false);
        try {
            CloseableHttpClient client = HttpClients.createDefault();
            HttpGet get = new HttpGet(url);
            CloseableHttpResponse httpResponse;
            httpResponse = client.execute(get);
            int code = httpResponse.getStatusLine().getStatusCode();
            String str = "";
            if (code == NUMBER) {
                HttpEntity entity = httpResponse.getEntity();
                str = EntityUtils.toString(entity, "utf-8");
                rj.setResult(true);
                rj.setMessage(str);
            } else {
                rj.setMessage("http client get handle failed with code:" + code);
            }
        } catch (Exception ex) {
            rj.setMessage(ex.getMessage());
        }
        return rj;
    }

    /**
     * 
     * httpPost,(httpPost). <br/>
     * Author: qiaocf <br/>
     * Create Date: 2016年3月11日 <br/>
     * ===============================================================<br/>
     * Modifier: qiaocf <br/>
     * Modify Date: 2016年3月11日 <br/>
     * Modify Description: <br/>
     * ===============================================================<br/>
     * 
     * @param url 地址
     * @param body body
     * @return ResultJson
     * @since JDK 1.7
     */
    public static ResultJson httpPost(String url, String body) {
        ResultJson rj = new ResultJson(false);
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        CloseableHttpClient closeableHttpClient = httpClientBuilder.build();
        try {
            HttpPost httpPost = new HttpPost(url);
            StringEntity entity = new StringEntity(body, "utf-8");
            httpPost.setEntity(entity);
            HttpResponse httpResponse = closeableHttpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();
            if (httpEntity != null) {
                String result = EntityUtils.toString(httpEntity, "UTF-8");
                rj.setResult(true);
                rj.setMessage(result);
            } else {
                rj.setMessage("http client post handle failed with null entity");
            }
            closeableHttpClient.close();
        } catch (Exception ex) {
            rj.setMessage(ex.getMessage());
        } finally {
            if (closeableHttpClient != null) {
                try {
                    closeableHttpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return rj;
    }

    /**
     * http post 文件到服务器
     * 
     * @param url url地址
     * @param file 文件
     * @return 成功与否以及返回数据
     */
    public static ResultJson httpPostFile(String url, File file) {
        ResultJson rj = new ResultJson(false);
        if (file != null) {
            HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
            CloseableHttpClient closeableHttpClient = httpClientBuilder.build();
            try {
                HttpPost httpPost = new HttpPost(url);
                MultipartEntity reqEntity = new MultipartEntity();
                reqEntity.addPart("files", new FileBody(file));
                httpPost.setEntity(reqEntity);
                HttpResponse httpResponse = closeableHttpClient.execute(httpPost);
                HttpEntity httpEntity = httpResponse.getEntity();
                if (httpEntity != null) {
                    String result = EntityUtils.toString(httpEntity, "UTF-8");
                    rj.setResult(true);
                    rj.setMessage(result);
                } else {
                    rj.setMessage("http client post handle failed with null entity");
                }
                closeableHttpClient.close();
            } catch (Exception ex) {
                rj.setMessage(ex.getMessage());
            } finally {
                if (closeableHttpClient != null) {
                    try {
                        closeableHttpClient.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return rj;
    }
    
    /** 
	 * 批量文件 http post 到服务器
	 * @param url
	 * @param files
	 * @return 成功与否以及返回数据
	 */
	public static ResultJson httpPostFiles(String url,File[] files){
		ResultJson rj = new ResultJson(false);
		if(files != null){
			HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
			CloseableHttpClient closeableHttpClient = httpClientBuilder.build();
			try {	
				HttpPost httpPost = new HttpPost(url); 	
				MultipartEntity reqEntity = new MultipartEntity();
				for(File file:files){
					reqEntity.addPart("files", new FileBody(file));
				}	 
				httpPost.setEntity(reqEntity);
				HttpResponse httpResponse = closeableHttpClient.execute(httpPost);
				HttpEntity httpEntity = httpResponse.getEntity();
				if (httpEntity != null) {
					String result = EntityUtils.toString(httpEntity, "UTF-8");
					rj.setResult(true);
				    rj.setMessage(result);
				} else {
					rj.setMessage("http client post handle failed with null entity");
				}
				closeableHttpClient.close();
			} catch (Exception ex){
				rj.setMessage(ex.getMessage());
			} finally {
				if(closeableHttpClient != null){
					try {
						closeableHttpClient.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}		
		return rj;
	}
}
